(function(){
let regJs=/\.js$/;
let regHTML=/\.(html|htm)$/;
let regHttp=/^(http|https):/i;
var globalId=Object.create(null);

  /* 
     {

        name:{
             name:'cmt_1',
             rule:'leftList',
             path:'./pages/test0.html'
        },
        
     }
  
  */
var errMsg1=
`router.getComponent({
    app      : Eng instance object,
    hashId   : hash Name,
    parentId : Requesting the parent dom ID of the component, matching based on the e-id directive of the parent component,
    data     :  Data passed to the opening component ,
    callBack( component App){
        //When everything is ready, if needed
    }
})`;


var Router=function(cfg){
    var t=this;
    var $=Object.create(null); 
        t.type=cfg.type;
        // t.init();

        t.initCfg(cfg,$);
        // t.initRules(cfg.rules);
        // t.initData=null;
        // t.initRules=null;
        t.initCfg=null;
        t.loadInit(cfg,$);
        t.loadInit=null;
};

    //组件数据转化到  idMap 
    Router.prototype.initCfg=function(cfg,$){
        let t=this;
        let k='',d,u;
        let parent='',rule='',cache,wait,hash;
        let data=cfg.data,rules=cfg.rules||{};
        let DEV=t.dev;
        let IdMap=Object.create(null);
        // let parents=Object.create(null);
            //
            $.rules=rules;
            $.IdMap=IdMap;
            //
            for(k in data){
                d=data[k];
                parent=d.parentId;
                if(parent){
                        rule=d.rule;
                        cache=d.cacheMode?d.cacheMode.trim():'none';
                        if(d.components instanceof Array){
                            d.components.forEach(function(o,i){
                                    let id=o.id;
                                        if(id===u){
                                            console.error("The component must define an id!");
                                            return
                                        };
                                        if(IdMap[id]===u&&globalId[id]===u){
                                            // if(o.parentId===u)o.parentId=parent;
                                            o.parentId=parent;
                                            if(o.cacheMode===u)o.cacheMode=cache;
                                            o.rule=rule;
                                            o.hash=true;
                                            if(o.rule){
                                                let ruleCfg=rules[o.rule]||{type:'only'};
                                                    // 
                                                    ruleCfg.components=[];
                                                    ruleCfg.lastId='';
                                                    // 
                                                    o.rule=ruleCfg;
                                                    IdMap[id]=o;
                                                    globalId[id]=o;
                                                    // if(!DEV){
                                                    //     o.ready=true;
                                                    //     Eng.addComponent(id,o.path);
                                                    // };
                                            }else{
                                                console.error("Component must have 'rule' parameter either public or private!")
                                            };
                                        }else{
                                                console.error("Each component's ID name is globally unique =>  "+id);
                                        };
                                        
                            }); 
                        };
                }else{
                    console.error("Each group of components must specify a parentId (e-id) !!");
                };
            };
             
    };

    Router.prototype.loadInit=function(cfg,$){
        let t=this,u;
        let DEV=typeof(Eng_DEV_Tools)!=='undefined'?true:false;
        let APP=null;
        let mode=cfg.mode;
        // let rules=t.rules;
        let IdMap=$.IdMap;
        let error=cfg.error||{};
        let DEF=cfg.default||{};
        let errF=0;
        let deF=0;
        let LS=localStorage,SS=sessionStorage,HS=history;
        let PID=Object.create(null);
        let DM=Object.create(null);
        let DMrr=[],DMO=null,DMS=0;
            /**
             * 通过路由加载组件 
             * @param {*} cfg ={
             *               hashId:'',  
             *            }
             * 
             * @param {*} callBack 
             * @returns 
             */
            t.setComponent=function(cfg){
                      if(APP===null){
                         console.error('The "Eng" object instance that controls Router does not exist!! You must set it via Router.setHost( ...) '); 
                         return;
                      };
                  let id=cfg.id,u;
                  let cmt= IdMap[id];
                      if(!cmt){
                          console.warn("The component with id = "+id+" cannot be matched!")
                          return
                      };
                  let rule=cmt.rule;
                  let type=rule.type;
                  let onlyF=false;
                      if(type==='only'||type==='only-sleep'||type==='only-coexist'){
                                  onlyF=true;
                                  if($.typeHandle(cmt,cfg)===false){
                                        let pid=cmt.parentId;
                                        let lastId=rule.lastId;
                                            PID[pid]=id;
                                            rule.lastId=id;
                                            // Create new component
                                            $.setHash( id ,  lastId, cmt , cfg.config);
                                  }else{
                                            // Wake up existing sleeping component
                                            $.setHash( id ,  rule.lastId , null );
                                            return;
                                  };
                            
                      };  
                      if(rule.interceptor instanceof Function){
                            rule.interceptor(cfg,function(flag){
                                if(flag)$.requestComponent(id,cmt,cfg,onlyF);
                            });
                      }else{
                            $.requestComponent(id,cmt,cfg,onlyF);
                      };     
            };
            
            $.requestComponent=function(id,cmt,cfg,onlyF){
                   //  
                   if(cmt.ready){
                        Eng.getComponentById(id,function(module){
                            if(module===null)return;
                            
                            if(onlyF){
                                let pid=cmt.parentId;
                                    if(PID[pid]===id){
                                       $.setComponent(cmt , cfg , module);
                                    }else{
                                        //终止前一个请求的操作 
                                        console.log('111111111111111')
                                    }
                            }else{ 
                                $.setComponent(cmt , cfg , module);
                            };
                       });
                   }else if(DEV){
                            Eng.addComponent(id,cmt.path,function(module){
                                if(module===null)return;
                                cmt.ready=true;
                                if(onlyF){
                                    let pid=cmt.parentId;
                                        if(PID[pid]===id){
                                            // debugger
                                            $.setComponent(cmt , cfg , module);
                                        }else{
                                            //终止前一个请求的操作 
                                            console.log('111111111111111')
                                        }
                                }else{ 
                                    $.setComponent(cmt , cfg , module);
                                };
                            });
                   }else{
                        console.err('Please check whether you are in the development mode where "Eng_DEV_Tools" is located, and the requested component path is html suffix.')
                   };
            };
            
            $.htmlToJs=function(id,path,callBack){
                    Eng_DEV_Tools.htmlToJs(path,function(flag){
                            if(flag)callBack(true);
                    });
            };
            $.setComponent=function(cmt,cfg,module){
                let app=null;
                    if(module){
                            let rule=cmt.rule;
                                app=module( $.mixData(cfg.config , cmt.config));
                                app.$_routerId=cmt.id;
                                
                                rule.components.push(app);
                                

                            var parent=APP.$_idDoms[cmt.parentId];
                                if(parent){    
                                       parent.appendChild(app.$_el);
                                }else{
                                       console.error(errMsg1);
                                };
                    };
                    if(cfg.callBack)cfg.callBack(app);
            };
            
            $.mixData=function(o0,o1){
                let o=o0||{},k='',d,u;
                    for(k in o1){
                        if(o[k]===u){
                            d=o1[k];
                            try {
                                o[k]=JSON.parse(JSON.stringify(d));
                            } catch (err) {
                                
                            }
                        };
                    };
                    return o;
            };

            /**
             * 按索引删除
             */
            $.removeByIndex=function(n){
                let arr=this.components;
                let o=arr[n];
                    if(o!==u){
                        o.$_destroy();
                        arr.splice(n,1);
                        return true
                    };
                    return false;      
            };

            /**
             * 删除 component 
             */
            $.removeComponent=function(o){
                 let arr=o.$_routerComponents;
                 let n=arr.indexOf(o);
                     if(n>-1){
                           o.$_destroy();
                           arr.splice(n,1);
                           return true;
                     };
                     return false; 
            };

            /**
             * 根据不同的元素预处理 
             */
            $.typeHandle=function(cmt,cfg){
                let id=cmt.id,F=false,o,u;
                let CB=cfg.callBack;
                let rule=cmt.rule;
                let type=rule.type;
                let arr=rule.components,i=0,l=arr.length;
                switch(type){
                    case  'only':        // 唯一显示 , 销毁其它
                        o=arr[0];
                        if(o!==u){
                             if(o.$_routerId===id){
                                  F=true;
                                  if(CB)CB(o);
                             }else{
                                  o.$_destroy();
                                  arr.length=0;
                             };
                        };             
                    break;
                    case  'only-sleep':  // 唯一显示 , sleep其它 
                    //  debugger
                        while(i<l){
                            o=arr[i];
                            if(o.$_routerId===id){
                                o.$_awake();
                                if(CB)CB(o);
                                F=true
                            }else{
                                if(o.$_status==='active')rule.lastId=o.$_routerId;
                                o.$_sleep();
                            };
                            i++;
                        };    
                    break;
                    case  'only-coexist':// 显示 所有id不重复的元素 
                    // debugger
                        while(i<l){
                            o=arr[i];
                            if(o.$_routerId===id){
                                F=true;
                                if(CB)CB(o);
                                break;
                            };
                            i++;
                        };
                        rule.lastId='';   // 共存 ,上面已经判断唯一, 是否允许创建新的 , 之后都不存在删除操作,因此 设置为'' 空
                    break;
                    case  'coexist':     // 有多少显示多少 
                    break;
                    default:
                        console.warn('Rule type spelling error =>  "'+type+'"')
                        F=true;
                    break    
                }
                return F;    
            };

            t.getComponentsById=function(id){

            };

            t.getComponentsByRule=function(rule){
                 
            };

            t.setHost=function(app){
                APP=app;
                if($.getHash)$.getHash();
            };

            //销毁所有组件  
            t.destroyAll=function(){
                let k='',o,u;
                    for(k in IdMap){
                            o=IdMap[k];
                            o.rule.lastId='';
                            LS.removeItem(k);
                            SS.removeItem(k);
                            o.rule.components.forEach(function(a){
                                a.$_destroy();
                            });
                            o.rule.components.length=0;
                    };
                    for(k in PID){
                        PID[k]=u;
                    };
            };

            t.destroyGlobal=function(){
                let k='',o;
                    for(k in globalId){
                            o=globalId[k];
                            o.rule.lastId='';
                            LS.removeItem(k);
                            SS.removeItem(k);
                            
                            o.rule.components.forEach(function(a){
                                a.$_destroy();
                            });
                            o.rule.components.length=0;
                    };
                    for(k in PID){
                        PID[k]=u;
                    };
            };
            
            t.error=function(){
                let o=error;
                    t.destroyAll();
                    HS.replaceState(null,'','');
                    if(errF>0){
                        let destroy=o.destroy;
                            if(destroy==='global'){
                                    t.destroyGlobal();
                            }else if(destroy==='all'){
                                    t.destroyAll();
                            };
                            if(errF===1){
                                let time=o.delay<<0;
                                    DMS=2;
                                    if(time<1000)time=1000;
                                    Eng.getComponentById(o.id,function(fun){
                                            if(DMS!==2)return;
                                            $.destroyDM();
                                        var a=fun();
                                        var p=APP.$_idDoms[o.parentId]||document.body;
                                            p.appendChild(a.$_el);
                                            HS.replaceState(null,'',o.id);
                                            DMO=a;
                                            setTimeout(function(){
                                                HS.replaceState(null,'',o.targetId||'/');
                                                a.$_destroy();
                                                DMO=null;
                                                HS.go(0); 
                                            },time)
                                    });
                            };
                    }else if(errF===0){
                            let cb=function(module){
                                    if(module){
                                        errF=1;
                                        t.error();
                                    }else{
                                        errF=2;
                                    };
                                };
                                if(DEV){
                                    $.htmlToJs(o.id , o.path , function(flag){
                                        if(flag)Eng.addComponent( o.id , o.path , cb);  
                                    });
                               }else{
                                    Eng.addComponent( o.id , o.path , cb);  
                               };
                    };
            };
            
            $.addComponent=function(id,path,callBack){
                Eng.addComponent( id , path , function(module){
                     if(callBack)callBack(module);
                });
            };
            
            t.default=function(){
                let o=DEF;
                    t.destroyAll();
                    HS.replaceState(null,'','');
                 if(deF===1){
                      DMS=1;
                      Eng.getComponentById(o.id,function(fun){
                                if(DMS!==1)return;
                                $.destroyDM();
                            var a=fun(DEF.config);
                            var p=APP.$_idDoms[o.parentId]||document.body;
                                p.appendChild(a.$_el);
                                HS.replaceState(null,'',DEF.id);
                                DMO=a;
                                // HS.go(0); 
                      });
                 }else if(deF===0){
                       let cb=function(module){
                                if(module){
                                    deF=1;
                                    t.default();
                                }else{
                                    deF=2;
                                };
                             };
                        if(DEV){
                            $.htmlToJs(o.id , o.path , function(flag){
                                    if(flag)$.addComponent(o.id,o.path,cb); 
                            });
                        }else{
                              $.addComponent(o.id,o.path,cb); 
                        };
                 };
            };
            if(DEF.id&&DEF.path){
                DM[DEF.id]=t.default;
                DM['']=t.default;
                DM['/']=t.default;
                DMrr.push(DEF.id);
            };
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           
            if(error.id&&error.path){
                DM[error.id]=t.error;
                DMrr.push(error.id);
            };
            // 销毁默认 组件 和 error组件
            $.destroyDM=function(){
                DMS=0;
                if(DMO!==null){
                    HS.replaceState(null,'','');
                    DMO.$_destroy();
                    DMO=null;
                }
            };

            if(mode){
                let initF=true,setF=false;
                    $.getHash=function(){
                            if(setF){
                                setF=false;
                                return
                            };
                        var hash='',u;
                            if(mode==='hash'){
                                hash=decodeURI(location.hash).replace(/^\#/,'');
                            }else{//HS
                                hash=location.pathname; 
                            };
                        var arr= hash.split('/'),drr=[];
                            // console.log('hash   ===   '+ hash);
                            if(initF){
                                    initF=false;
                                    if(DM[hash]!==u){
                                        DM[hash]();
                                        return
                                    }else if($.firstComponent(arr)){
                                        return
                                    };
                                    arr.forEach(function(v){
                                            if(v==='')return;
                                                let o=IdMap[v];
                                                    if(o)t.setComponent({id:v,config:$.getCacheConfig(v,o)});
                                    });
                                    return;
                            }else{
                                    arr.forEach(function(v){
                                        if(v==='')return;
                                        drr.push(v)
                                    })
                            };
                            return drr;
                    };
                    //Open the default component for the first time
                    $.firstComponent=function(arr){
                        let l=DMrr.length,k='';
                            while(l--){
                                k=DMrr[l];
                                if(arr.indexOf(k)>-1){
                                    DM[k]();
                                    return true
                                };    
                            };
                            return false
                    };

                    $.getCacheConfig=function(id,cmt){
                        let cache=cmt.cacheMode,str,d,u;
                            if(cache!=='none'){
                                 if(cache==='local'){
                                       str=LS.getItem(id);
                                 }else{ //session
                                       str=SS.getItem(id);
                                 };
                                 if(str){
                                     try {
                                         d=JSON.parse(str);
                                     } catch (err) {
                                         d=u;
                                         throw err;
                                     }
                                 };
                                 console.log(id,d);
                                 return d;
                            };
                            return
                    };

                    $.removeHash=function(id){
                        let arr= $.getHash();
                        let n=arr.indexOf(id);
                            if(n<0)return false;
                            arr.splice(n,1);
                            if(mode==='hash'){
                                 setF=true;
                                 location.hash=arr.join('/');
                            }else{
                                 HS.replaceState(null,'',arr.join('/'));
                            };
                            return true;
                    };
               
                    $.setHash=function(newHash,oldHash,cmt,config){
                            if(newHash===oldHash)return;
                             $.destroyDM();
                        let arr= $.getHash(),u;
                        let n=arr.indexOf(oldHash);
                            // delete LoadingMethod[oldHash];
                            if(n>-1){
                                arr[n]=newHash;
                                
                            }else{ 
                                n=arr.indexOf(newHash);
                                if(n<0){
                                    arr.push(newHash)
                                }else{
                                    // 如果不设置return  hash相同 ,不会触发修改 setF 
                                    return;
                                };
                            };
                            if(cmt){
                                let cache=cmt.cacheMode;
                                    if(cache==='local'){
                                        try {
                                            LS.setItem(newHash,JSON.stringify(config||''))
                                        } catch (err) {
                                            throw err
                                        };
                                    }else if(cache==='session'){
                                        try {
                                            SS.setItem(newHash,JSON.stringify(config||''))
                                        } catch (err) {
                                            throw err
                                        };
                                    };
                           };    
                            if(mode==='hash'){
                                  setF=true; 
                                  location.hash=arr.join('/');
                            }else{  
                                  // HS.pushState(STATE,'', arr.join('/') );
                                  HS.replaceState(null,'',arr.join('/'));
                            };
                            
                    };
                    if(mode==='hash'){
                            window.addEventListener('hashchange',function(){
                                    $.getHash();
                            });

                    }else{
                              //只有当前进 后退时才会触发, 其它时候都不会 (输入地址属于刷新了)
                            window.addEventListener("popstate", function() {
                                    $.getHash();
                            });
                    };

            };

    };


window.Router=Router;
})();
